package com.jiajia.study.nio;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;

/**
 *
 * NIO　非阻塞式编程实现
 * @author : zjj
 * @date : 2021-04-21 14:21
 */
public class SocketNoBlockingClient {

    public static void main(String[] args) throws IOException {
        testServer();

        testClient();
    }


    private static void testClient() throws IOException {

        // 1 获取通道
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8888));

        // 2 切换非阻塞模式
        socketChannel.configureBlocking(false);

        // 3 分配指定大小的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);


        // 4 发送数据给服务端

            buffer.put((new Date().toString() + "\n" + "我很好呀").getBytes());
            buffer.flip();

            socketChannel.write(buffer);
            buffer.clear();


        // 5 关闭通道
        socketChannel.close();


    }

    private static void testServer() throws IOException {
        // 1 获取通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 2 切换非阻塞模式
        serverSocketChannel.configureBlocking(false);

        // 3 绑定连接
        serverSocketChannel.bind(new InetSocketAddress(8888));

        // 4 获取选择器
        Selector selector = Selector.open();

        // 5 将通道注册到选择器上面去，并且指定‘监听接收事件’

        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 6 轮训方式获取选择器上面已经就绪的事件
        while(selector.select() > 0){

            // 7 获取到当前选择器中所有的注册的‘选择键（已经就绪的监听事件）’
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            while(iterator.hasNext()){
                // 8 获取到就绪的事件
                SelectionKey next = iterator.next();

                // 9 判断类型，执行操作
                if(next.isAcceptable()){
                    // 10 如果是 ‘接收就绪’ 事件，获取客户端的连接
                    SocketChannel socketChannel = serverSocketChannel.accept();

                    // 11 切换非阻塞模式
                    socketChannel.configureBlocking(false);

                    // 12 将通道注册到选择器上面去
                    socketChannel.register(selector,SelectionKey.OP_READ);
                }else if(next.isReadable()){
                    // 13 获取当前选择器上  ‘读就绪’ 状态的通道
                    SocketChannel readSocktChannel = (SocketChannel) next.channel();
                    // 14 读取数据
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                    int len ;
                    while((len = readSocktChannel.read(byteBuffer)) != -1){
                        byteBuffer.flip();
                        System.out.println(new String(byteBuffer.array(),0,len));
                        byteBuffer.clear();
                    }
                }
                // 15 取消选择键 SelectionKey ,不然选择键一直存在的话，就会一直进行之前的操作
                iterator.remove();
            }
        }



    }
}
